/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-10
 * V4.0
 */
package com.jphenix.clazz;

import com.jphenix.standard.docs.ClassInfo;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * <code>Code_attribute</code>.
 *
 * <p>To browse the <code>code</code> field of
 * a <code>Code_attribute</code> structure,
 * use <code>CodeIterator</code>.
 *
 * @author mabg
 * @see CodeIterator
 * @see #iterator()
 */
@ClassInfo({"2014-06-10 19:49","代码属性信息类"})
public class CodeAttribute extends AttributeInfo implements Opcode {
    
    /**
     * The name of this attribute <code>"Code"</code>.
     */
    public static final String tag = "Code";

    // code[] is stored in AttributeInfo.info.

    private int maxStack;
    private int maxLocals;
    private ExceptionTable exceptions;
    private ArrayList<AttributeInfo> attributes;

    /**
     * Constructs a <code>Code_attribute</code>.
     *
     * @param cp        constant pool table
     * @param stack     <code>max_stack</code>
     * @param locals    <code>max_locals</code>
     * @param code      <code>code[]</code>
     * @param etable    <code>exception_table[]</code>
     */
    public CodeAttribute(ConstPool cp, int stack, int locals, byte[] code,
                         ExceptionTable etable)
    {
        super(cp, tag);
        maxStack = stack;
        maxLocals = locals;
        info = code;
        exceptions = etable;
        attributes = new ArrayList<AttributeInfo>();
    }


    CodeAttribute(ConstPool cp, int name_id, DataInputStream in)
        throws IOException
    {
        super(cp, name_id, (byte[])null);
        in.readInt();

        maxStack = in.readUnsignedShort();
        maxLocals = in.readUnsignedShort();

        int code_len = in.readInt();
        info = new byte[code_len];
        in.readFully(info);

        exceptions = new ExceptionTable(cp, in);

        attributes = new ArrayList<AttributeInfo>();
        int num = in.readUnsignedShort();
        for (int i = 0; i < num; ++i) {
            attributes.add(AttributeInfo.read(cp, in));
        }
    }

    /**
     * Returns the length of this <code>attribute_info</code>
     * structure.
     * The returned value is <code>attribute_length + 6</code>.
     */
    @Override
    public int length() {
        return 18 + info.length + exceptions.size() * 8
               + AttributeInfo.getLength(attributes);
    }

    /**
     * This method is not available.
     *
     * @throws java.lang.UnsupportedOperationException  always thrown.
     */
    @Override
    public byte[] get() {
        throw new UnsupportedOperationException("CodeAttribute.get()");
    }


    /**
     * Returns the name of the class declaring the method including
     * this code attribute.
     */
    public String getDeclaringClass() {
        ConstPool cp = getConstPool();
        return cp.getClassName();
    }

    /**
     * Returns <code>max_stack</code>.
     */
    public int getMaxStack() {
        return maxStack;
    }

    /**
     * Computes the maximum stack size and sets <code>max_stack</code>
     * to the computed size.
     *
     * @throws Exception      if this method fails in computing.
     * @return the newly computed value of <code>max_stack</code>
     */
    public int computeMaxStack() throws Exception {
        maxStack = new CodeAnalyzer(this).computeMaxStack();
        return maxStack;
    }

    /**
     * Returns <code>max_locals</code>.
     */
    public int getMaxLocals() {
        return maxLocals;
    }


    /**
     * Returns <code>code_length</code>.
     */
    public int getCodeLength() {
        return info.length;
    }

    /**
     * Returns <code>code[]</code>.
     */
    public byte[] getCode() {
        return info;
    }

    /**
     * Makes a new iterator for reading this code attribute.
     */
    public CodeIterator iterator() {
        return new CodeIterator(this);
    }

    /**
     * Returns <code>exception_table[]</code>.
     */
    public ExceptionTable getExceptionTable() { return exceptions; }

    /**
     * Returns <code>attributes[]</code>.
     * It returns a list of <code>AttributeInfo</code>.
     * A new element can be added to the returned list
     * and an existing element can be removed from the list.
     *
     * @see AttributeInfo
     */
    public List<AttributeInfo> getAttributes() { return attributes; }

    /**
     * Returns the attribute with the specified name.
     * If it is not found, this method returns null.
     *
     * @param name      attribute name
     * @return          an <code>AttributeInfo</code> object or null.
     */
    public AttributeInfo getAttribute(String name) {
        return AttributeInfo.lookup(attributes, name);
    }
}
